# 工作流引擎模型
from django.db import models
from django.contrib.auth.models import User
from django.utils import timezone
import json


class WorkflowTemplate(models.Model):
    """工作流模板模型"""
    TEMPLATE_TYPE_CHOICES = [
        ('asset_transfer', '资产调拨'),
        ('asset_borrow', '资产借用'),
        ('maintenance_request', '维修申请'),
        ('asset_scrap', '资产报废'),
        ('inventory_plan', '盘点计划'),
        ('custom', '自定义'),
    ]
    
    name = models.CharField(max_length=200, verbose_name="模板名称")
    template_type = models.CharField(max_length=50, choices=TEMPLATE_TYPE_CHOICES, verbose_name="模板类型")
    description = models.TextField(blank=True, verbose_name="模板描述")
    
    # 流程定义, 例如:
    # {
    #     "steps": [
    #         {
    #             "id": "step1",
    #             "name": "经理审批",
    #             "type": "manual",
    #             "assignee_group": "Manager"
    #         }
    #     ],
    #     "completion_actions": {
    #         "on_approve": {
    #             "set_status": "borrowed",
    #             "set_user": "{{applicant}}"
    #         },
    #         "on_reject": {
    #             "set_status": "idle"
    #         }
    #     }
    # }
    workflow_definition = models.JSONField(verbose_name="流程定义")
    
    # 状态信息
    is_active = models.BooleanField(default=True, verbose_name="是否启用")
    version = models.CharField(max_length=20, default='1.0', verbose_name="版本号")
    
    created_by = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, verbose_name="创建人")
    created_at = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")
    updated_at = models.DateTimeField(auto_now=True, verbose_name="更新时间")
    
    class Meta:
        verbose_name = "工作流模板"
        verbose_name_plural = "工作流模板"
        ordering = ['-created_at']
    
    def __str__(self):
        return f"{self.name} (v{self.version})"
    
    def get_steps(self):
        """获取流程步骤"""
        return self.workflow_definition.get('steps', [])
    
    def get_step_by_id(self, step_id):
        """根据ID获取步骤"""
        for step in self.get_steps():
            if step.get('id') == step_id:
                return step
        return None


class WorkflowInstance(models.Model):
    """工作流实例模型"""
    INSTANCE_STATUS_CHOICES = [
        ('pending', '待处理'),
        ('running', '运行中'),
        ('completed', '已完成'),
        ('cancelled', '已取消'),
        ('failed', '失败'),
        ('suspended', '已暂停'),
    ]
    
    template = models.ForeignKey(WorkflowTemplate, on_delete=models.CASCADE, verbose_name="工作流模板")
    instance_name = models.CharField(max_length=200, verbose_name="实例名称")
    status = models.CharField(max_length=20, choices=INSTANCE_STATUS_CHOICES, default='pending', verbose_name="实例状态")
    
    # 关联对象信息
    related_object_type = models.CharField(max_length=50, verbose_name="关联对象类型")
    related_object_id = models.PositiveIntegerField(verbose_name="关联对象ID")
    
    # 流程数据
    workflow_data = models.JSONField(default=dict, verbose_name="流程数据")
    current_step_id = models.CharField(max_length=50, blank=True, verbose_name="当前步骤ID")
    
    # 时间信息
    started_at = models.DateTimeField(null=True, blank=True, verbose_name="开始时间")
    completed_at = models.DateTimeField(null=True, blank=True, verbose_name="完成时间")
    
    created_by = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, verbose_name="创建人")
    created_at = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")
    updated_at = models.DateTimeField(auto_now=True, verbose_name="更新时间")
    
    class Meta:
        verbose_name = "工作流实例"
        verbose_name_plural = "工作流实例"
        ordering = ['-created_at']
        indexes = [
            models.Index(fields=['status', '-created_at']),
            models.Index(fields=['related_object_type', 'related_object_id']),
        ]
    
    def __str__(self):
        return f"{self.instance_name} - {self.get_status_display()}"
    
    def start(self):
        """启动工作流"""
        if self.status != 'pending':
            raise ValueError("只有待处理状态的工作流才能启动")
        
        self.status = 'running'
        self.started_at = timezone.now()
        
        # 找到第一个步骤
        steps = self.template.get_steps()
        if steps:
            first_step = steps[0]
            self.current_step_id = first_step.get('id')
            
            # 创建第一个步骤任务
            self._create_step_task(first_step)
        
        self.save()
    
    def complete_step(self, step_id, result_data=None):
        """完成步骤"""
        if self.current_step_id != step_id:
            raise ValueError("步骤ID不匹配")
        
        current_step = self.template.get_step_by_id(step_id)
        if not current_step:
            raise ValueError("步骤不存在")
        
        # 更新流程数据
        if result_data:
            self.workflow_data.update(result_data)
        
        # 查找下一个步骤
        next_step = self._get_next_step(current_step)
        
        if next_step:
            self.current_step_id = next_step.get('id')
            self._create_step_task(next_step)
        else:
            # 没有下一步，完成工作流
            self.status = 'completed'
            self.completed_at = timezone.now()
            self.current_step_id = ''
        
        self.save()
    
    def cancel(self, reason=''):
        """取消工作流"""
        self.status = 'cancelled'
        self.workflow_data['cancel_reason'] = reason
        self.save()
        
        # 取消所有待处理的任务
        self.step_tasks.filter(status='pending').update(status='cancelled')
    
    def _get_next_step(self, current_step):
        """获取下一个步骤"""
        steps = self.template.get_steps()
        current_index = -1
        
        for i, step in enumerate(steps):
            if step.get('id') == current_step.get('id'):
                current_index = i
                break
        
        if current_index >= 0 and current_index < len(steps) - 1:
            return steps[current_index + 1]
        
        return None
    
    def _create_step_task(self, step):
        """创建步骤任务"""
        return WorkflowStepTask.objects.create(
            workflow_instance=self,
            step_id=step.get('id'),
            step_name=step.get('name'),
            step_type=step.get('type', 'manual'),
            assignee_id=step.get('assignee_id'),
            step_config=step.get('config', {}),
            status='pending'
        )


class WorkflowStepTask(models.Model):
    """工作流步骤任务模型"""
    TASK_STATUS_CHOICES = [
        ('pending', '待处理'),
        ('in_progress', '处理中'),
        ('completed', '已完成'),
        ('rejected', '已拒绝'),
        ('cancelled', '已取消'),
        ('failed', '失败'),
    ]
    
    STEP_TYPE_CHOICES = [
        ('manual', '人工审批'),
        ('auto', '自动处理'),
        ('notification', '通知'),
        ('condition', '条件判断'),
        ('parallel', '并行处理'),
    ]
    
    workflow_instance = models.ForeignKey(WorkflowInstance, on_delete=models.CASCADE, verbose_name="工作流实例", related_name='step_tasks')
    step_id = models.CharField(max_length=50, verbose_name="步骤ID")
    step_name = models.CharField(max_length=200, verbose_name="步骤名称")
    step_type = models.CharField(max_length=20, choices=STEP_TYPE_CHOICES, verbose_name="步骤类型")
    
    # 任务分配
    assignee = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True, verbose_name="处理人")
    assigned_at = models.DateTimeField(null=True, blank=True, verbose_name="分配时间")
    
    # 任务状态
    status = models.CharField(max_length=20, choices=TASK_STATUS_CHOICES, default='pending', verbose_name="任务状态")
    
    # 步骤配置和结果
    step_config = models.JSONField(default=dict, verbose_name="步骤配置")
    result_data = models.JSONField(default=dict, verbose_name="处理结果")
    comments = models.TextField(blank=True, verbose_name="处理意见")
    
    # 时间信息
    started_at = models.DateTimeField(null=True, blank=True, verbose_name="开始时间")
    completed_at = models.DateTimeField(null=True, blank=True, verbose_name="完成时间")
    due_date = models.DateTimeField(null=True, blank=True, verbose_name="截止时间")
    
    created_at = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")
    updated_at = models.DateTimeField(auto_now=True, verbose_name="更新时间")
    
    class Meta:
        verbose_name = "工作流步骤任务"
        verbose_name_plural = "工作流步骤任务"
        ordering = ['-created_at']
        indexes = [
            models.Index(fields=['assignee', 'status', '-created_at']),
            models.Index(fields=['workflow_instance', 'step_id']),
        ]
    
    def __str__(self):
        return f"{self.workflow_instance.instance_name} - {self.step_name}"
    
    def assign_to(self, user):
        """分配任务给用户"""
        self.assignee = user
        self.assigned_at = timezone.now()
        self.save()
    
    def start_processing(self):
        """开始处理任务"""
        if self.status != 'pending':
            raise ValueError("只有待处理状态的任务才能开始处理")
        
        self.status = 'in_progress'
        self.started_at = timezone.now()
        self.save()
    
    def complete(self, result_data=None, comments=''):
        """完成任务"""
        if self.status not in ['pending', 'in_progress']:
            raise ValueError("任务状态不正确")
        
        self.status = 'completed'
        self.completed_at = timezone.now()
        self.comments = comments
        
        if result_data:
            self.result_data = result_data
        
        self.save()
        
        # 通知工作流实例完成步骤
        self.workflow_instance.complete_step(self.step_id, result_data)
    
    def reject(self, comments=''):
        """拒绝任务"""
        self.status = 'rejected'
        self.completed_at = timezone.now()
        self.comments = comments
        self.save()
        
        # 可以根据配置决定是否终止整个工作流
        if self.step_config.get('reject_terminates_workflow', True):
            self.workflow_instance.cancel(f"步骤 {self.step_name} 被拒绝: {comments}")
    
    @property
    def is_overdue(self):
        """判断是否超期"""
        if self.due_date and self.status in ['pending', 'in_progress']:
            return timezone.now() > self.due_date
        return False
    
    @property
    def processing_time(self):
        """计算处理时长"""
        if self.started_at and self.completed_at:
            return self.completed_at - self.started_at
        return None


class WorkflowHistory(models.Model):
    """工作流历史记录模型"""
    ACTION_CHOICES = [
        ('create', '创建'),
        ('start', '启动'),
        ('step_complete', '步骤完成'),
        ('step_reject', '步骤拒绝'),
        ('assign', '任务分配'),
        ('complete', '完成'),
        ('cancel', '取消'),
        ('suspend', '暂停'),
        ('resume', '恢复'),
    ]
    
    workflow_instance = models.ForeignKey(WorkflowInstance, on_delete=models.CASCADE, verbose_name="工作流实例", related_name='history_records')
    step_task = models.ForeignKey(WorkflowStepTask, on_delete=models.SET_NULL, null=True, blank=True, verbose_name="步骤任务")
    
    action = models.CharField(max_length=20, choices=ACTION_CHOICES, verbose_name="操作类型")
    operator = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, verbose_name="操作人")
    
    # 操作详情
    description = models.TextField(verbose_name="操作描述")
    old_value = models.JSONField(blank=True, null=True, verbose_name="变更前值")
    new_value = models.JSONField(blank=True, null=True, verbose_name="变更后值")
    
    created_at = models.DateTimeField(auto_now_add=True, verbose_name="操作时间")
    
    class Meta:
        verbose_name = "工作流历史"
        verbose_name_plural = "工作流历史"
        ordering = ['-created_at']
    
    def __str__(self):
        return f"{self.workflow_instance.instance_name} - {self.get_action_display()}"
    
    @classmethod
    def log_action(cls, workflow_instance, action, operator, description, step_task=None, old_value=None, new_value=None):
        """记录工作流操作"""
        return cls.objects.create(
            workflow_instance=workflow_instance,
            step_task=step_task,
            action=action,
            operator=operator,
            description=description,
            old_value=old_value,
            new_value=new_value
        )